package cc.spider.web.parser;

import cc.spider.web.exception.ParserException;
import org.jetbrains.annotations.NotNull;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.*;

public class JsoupElements implements IElements<JsoupElement, JsoupElements> {
    private Elements elements;
    private int size;

    public JsoupElements(Elements elements) {
        this.elements = elements;
        this.size = elements.size();
    }

    @Override
    public JsoupElement query(String selector) {
        return new JsoupElement(this.elements.get(0).select(selector).get(0));
    }

    @Override
    public JsoupElements queryAll(String selector) {
        return new JsoupElements(this.elements.select(selector));
    }

    @Override
    public JsoupElements children() {
        Elements elements = new Elements();
        for (Element element : this.elements) {
            Elements children = element.children();
            elements.addAll(children);
        }
        return new JsoupElements(elements);
    }

    @Override
    public JsoupElements children(String selector) {
        Elements elements = new Elements();
        Elements els = this.elements.select(selector);
        for (Element element : els) {
            Elements children = element.children();
            elements.addAll(children);
        }
        return new JsoupElements(elements);
    }

    @Override
    public JsoupElement get(int idx) {
        return new JsoupElement(this.elements.get(idx));
    }

    @Override
    public JsoupElements sub(int fromIndex, int toIndex) {
        List<Element> list = this.elements.subList(fromIndex, toIndex);
        Elements elements = new Elements();
        elements.addAll(list);
        return new JsoupElements(elements);
    }

    @Override
    public List<String> attr(String attrName) {
        List<String> list = new ArrayList<>();
        for (Element element : elements) {
            list.add(element.attr(attrName));
        }
        return list;
    }

    @Override
    public String content() {
        return elements.html();
    }

    @Override
    public String source() {
        return elements.outerHtml();
    }

    @Override
    public String toString() {
        return this.source();
    }

    @Override
    public String text() {
        return this.elements.text();
    }

    @Override
    public List<String> absUrl(String type) {

        if (null == type) {
            return this.absUrl();
        } else {
            List<String> urls = new ArrayList<>(this.elements.size());
            for (Element element : this.elements) {
                urls.add(element.absUrl(type));
            }
            return urls;
        }
    }

    @Override
    public List<String> absUrl() {
        List<String> urls = new ArrayList<>(this.elements.size());
        String[] urlKeys = new String[]{"href", "src"};
        for (Element element : this.elements) {
            for (String key : urlKeys) {
                if (element.hasAttr(key)) {
                    urls.add(element.absUrl(key));
                }
            }
        }
        return urls;
    }

    @Override
    public List<String> val() {
        List<String> list = new ArrayList<>(this.elements.size());
        for (Element element : elements) {
            list.add(element.val());
        }
        return list;
    }

    @NotNull
    @Override
    public Iterator<JsoupElement> iterator() {
        return new JsoupElements.Itr();
    }

    private class Itr implements Iterator<JsoupElement> {
        int cursor;
        int lastRet = -1;

        public boolean hasNext() {
            return this.cursor != JsoupElements.this.size;
        }

        public JsoupElement next() {
            int i = this.cursor;
            if (i >= JsoupElements.this.size) {
                throw new NoSuchElementException();
            } else {
                Elements elementData = JsoupElements.this.elements;
                if (i >= elementData.size()) {
                    throw new ConcurrentModificationException();
                } else {
                    this.cursor = i + 1;
                    return new JsoupElement(elementData.get(this.lastRet = i));
                }
            }
        }
    }
}
